package services

import (
	"errors"
	"fmt"
	"strconv"
	"time"

	"yuanaiproblem/dao"
	models "yuanaiproblem/dao/model"
	"yuanaiproblem/migrations/db"
	"yuanaiproblem/models/dto"

	"gorm.io/gorm"
)

// CreatePaper 创建试卷并关联题目
func CreatePaper(
	creatorID int32,
	title, description string,
	totalScore int32,
	questionIDs []int32,
) (*models.Paper, error) {
	existingIDs, err := dao.FindValidQuestionIDs(questionIDs)
	if err != nil {
		return nil, fmt.Errorf("验证题目ID失败: %w", err)
	}

	if len(existingIDs) == 0 {
		return nil, errors.New("所有题目ID均无效, 无法创建试卷")
	}

	if totalScore < int32(len(questionIDs)) {
		return nil, errors.New("总分不能小于题目数量")
	}

	var createdPaper *models.Paper
	err = db.DB.Transaction(func(tx *gorm.DB) error {
		paper := &models.Paper{
			Title:       title,
			Description: description,
			TotalScore:  totalScore,
			CreatorID:   creatorID,
			CreatedAt:   time.Now(),
			UpdatedAt:   time.Now(),
		}
		if err := dao.CreatePaper(tx, paper); err != nil {
			return err
		}

		paperQuestions := make([]models.PaperQuestion, len(existingIDs))
		for i, questionID := range existingIDs {
			paperQuestions[i] = models.PaperQuestion{
				PaperID:       paper.ID,
				QuestionID:    questionID,
				QuestionOrder: int32(i + 1),
				Score:         totalScore / int32(len(questionIDs)),
				CreatedAt:     time.Now(),
			}
		}
		if err := dao.CreatePaperQuestions(tx, paperQuestions); err != nil {
			return err
		}

		createdPaper = paper
		return nil
	})
	if err != nil {
		return nil, err
	}

	return createdPaper, nil
}

// GetPapersByUserID 根据用户ID查询试卷-查询未被删除的试卷
func GetPapersByUserID(userID int32) ([]*models.Paper, error) {
	//根据userId获取其试卷
	papers, err := dao.GetPapersByUserID(userID)
	if err != nil {
		return nil, errors.New("查询试卷列表失败: " + err.Error())
	}

	var responses []*models.Paper
	for _, paper := range papers {
		responses = append(responses, &models.Paper{
			ID:          paper.ID,
			Title:       paper.Title,
			Description: paper.Description,
			TotalScore:  paper.TotalScore,
			CreatorID:   paper.CreatorID,
			CreatedAt:   paper.CreatedAt,
			UpdatedAt:   paper.UpdatedAt,
		})
	}

	return responses, nil
}

// UpdateQuestionOrder 更新试卷中题目的顺序
func UpdateQuestionOrder(paperID uint, questions []dto.QuestionOrderItem) error {
	//根据试卷id进行查询
	_, err := dao.GetPaperByID(paperID)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.New("试卷不存在")
		}
		return err
	}

	return db.DB.Transaction(func(tx *gorm.DB) error {
		questionIDs := make([]uint, len(questions))
		for i, item := range questions {
			questionIDs[i] = item.QuestionID
		}

		count, err := dao.CountPaperQuestions(tx, paperID, questionIDs)
		if err != nil {
			return err
		}

		if count != int64(len(questions)) {
			return errors.New("部分题目不属于该试卷")
		}

		return dao.UpdateQuestionOrder(tx, paperID, questions)
	})
}

// GetUserPapers 查询指定用户的所有试卷
func GetUserPapers(params dto.UserPapersQuery) ([]models.Paper, int64, error) {
	return dao.GetUserPapers(params.UserID, params.Page, params.PageSize)
}

// GetUserPapers 查询指定用户的所有试卷(包含已删除的)
func GetUserAllPapers(params dto.UserPapersQuery) ([]models.Paper, int64, error) {
	return dao.GetUserAllPapers(params.UserID, params.Page, params.PageSize)
}

// RemoveQuestionFromPaper 从试卷中移除题目
func RemoveQuestionFromPaper(paperID, questionID uint) error {
	return db.DB.Transaction(func(tx *gorm.DB) error {
		pq, err := dao.GetPaperQuestion(tx, paperID, questionID)
		if err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return errors.New("试卷与题目关联不存在")
			}
			return err
		}

		deletedOrder := pq.QuestionOrder

		if err := dao.DeletePaperQuestion(tx, pq); err != nil {
			return err
		}

		if err := dao.UpdateQuestionOrdersAfterDelete(tx, paperID, deletedOrder); err != nil {
			return errors.New("更新题目顺序失败: " + err.Error())
		}

		return nil
	})
}

// DeletePaper 软删除试卷
func DeletePaper(paperID uint, currentUserID uint, role string) (time.Time, error) {
	paper, err := dao.GetPaperByID(paperID)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return time.Time{}, errors.New("试卷不存在")
		}
		return time.Time{}, err
	}

	if role != models.RoleAdmin && uint(paper.CreatorID) != currentUserID {
		return time.Time{}, errors.New("无权限删除此试卷")
	}

	if !paper.DeletedAt.Time.IsZero() {
		return paper.DeletedAt.Time, nil
	}

	deletedAt := time.Now()
	if err := dao.UpdatePaperDeletedAt(paper, deletedAt); err != nil {
		return time.Time{}, err
	}

	return deletedAt, nil
}

// GetPaperDetailByID 获取试卷详情
func GetPaperDetailByID(paperID uint, user *models.User) (*dto.PaperDetailResponse, error) {
	paper, err := dao.GetPaperByID(paperID)
	fmt.Println(paper)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("试卷不存在")
		}
		return nil, err
	}

	if paper.CreatorID != user.ID && user.Role != models.RoleAdmin {
		return nil, errors.New("无权查看该试卷")
	}

	paperQuestions, err := dao.GetPaperQuestionsWithDetails(paperID)
	if err != nil {
		return nil, errors.New("查询试卷题目失败: " + err.Error())
	}

	response := &dto.PaperDetailResponse{
		ID:          uint(paper.ID),
		Title:       paper.Title,
		Description: paper.Description,
		TotalScore:  int(paper.TotalScore),
		CreatorID:   int(paper.CreatorID),
		CreatedAt:   paper.CreatedAt,
		UpdatedAt:   paper.UpdatedAt,
		Questions:   make([]dto.PaperQuestionDetails, len(paperQuestions)),
	}

	for i, pq := range paperQuestions {
		question, err := dao.GetQuestionByIDForPaper(uint(pq.QuestionID))
		if err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return nil, errors.New("题目不存在: ID=" + strconv.Itoa(int(pq.QuestionID)))
			}
			return nil, errors.New("查询题目信息失败: " + err.Error())
		}

		response.Questions[i] = dto.PaperQuestionDetails{
			QuestionID:    uint(pq.QuestionID),
			Title:         question.Title,
			QuestionType:  question.QuestionType,
			Options:       question.Options,
			Answer:        question.Answer,
			Explanation:   question.Explanation,
			QuestionOrder: int(pq.QuestionOrder),
			Score:         int(pq.Score),
		}
	}

	return response, nil
}

// 根据试卷ID查询该试卷包含的所有题目（含详情）
func GetQuestionsByPaperID(paperID int32) ([]struct {
	models.PaperQuestion // 包含试卷与题目的关联信息（顺序、分值等）
	models.Question      // 包含题目的详细内容
}, error) {
	// 定义一个匿名结构体，用于接收关联查询结果
	var result []struct {
		models.PaperQuestion
		models.Question
	}

	// 执行关联查询
	err := db.DB.
		Table("paper_questions").                                              // 主表为试卷题目关联表
		Select("paper_questions.*, questions.*").                              // 查询所有字段
		Joins("JOIN questions ON paper_questions.question_id = questions.id"). // 关联题目表
		Where("paper_questions.paper_id = ?", paperID).                        // 筛选指定试卷
		Order("paper_questions.question_order ASC").                           // 按题目顺序排序
		Scan(&result).Error                                                    // 将结果扫描到result中

	return result, err
}

// AddQuestionToPaper 添加题目到试卷
func AddQuestionToPaper(paperID uint, req dto.AddQuestionToPaperRequest) (*models.PaperQuestion, error) {
	_, err := dao.GetPaperByID(paperID)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("试卷不存在")
		}
		return nil, err
	}

	_, err = dao.GetQuestionByIDForPaper(req.QuestionID)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("题目不存在")
		}
		return nil, err
	}

	exists, err := dao.CheckQuestionInPaper(paperID, req.QuestionID)
	if err != nil {
		return nil, err
	}
	if exists {
		return nil, errors.New("题目已存在于试卷中")
	}

	paperQuestion := &models.PaperQuestion{
		PaperID:       int32(paperID),
		QuestionID:    int32(req.QuestionID),
		QuestionOrder: int32(req.QuestionOrder),
		Score:         int32(req.Score),
		CreatedAt:     time.Now(),
	}

	if err := dao.CreatePaperQuestion(paperQuestion); err != nil {
		return nil, err
	}

	return paperQuestion, nil
}

// UpdatePaper 更新试卷信息
func UpdatePaper(paperID uint, req dto.UpdatePaperRequest, currentUserID int32, role string) (*models.Paper, error) {
	paper, err := dao.GetPaperByID(paperID)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("试卷不存在")
		}
		return nil, err
	}
	// 查询权限
	if role != models.RoleAdmin && paper.CreatorID != currentUserID {
		return nil, errors.New("无权限更新此试卷")
	}
	// 映射至map中
	updates := make(map[string]interface{})
	if req.Title != nil {
		updates["title"] = *req.Title
	}
	if req.Description != nil {
		updates["description"] = *req.Description
	}
	if req.TotalScore != nil {
		if *req.TotalScore <= 0 {
			return nil, errors.New("总分必须大于0")
		}
		updates["total_score"] = *req.TotalScore
	}

	if len(updates) > 0 {
		updates["updated_at"] = time.Now()
		if err := db.DB.Model(paper).Updates(updates).Error; err != nil {
			return nil, err
		}
		return dao.GetPaperByID(paperID)
	}

	return paper, nil
}

// AdminGetAllPaper 分页查询所有试卷
func AdminGetAllPaper(page, pageSize int) ([]models.Paper, int64, error) {
	return dao.GetAllPapers(page, pageSize)
}

// AdminGetPaperByID 根据ID查询试卷
func AdminGetPaperByID(paperId int) (*models.Paper, error) {
	//根据id进行查询paper
	return dao.GetPaperByID(uint(paperId))
}
